﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using winAppGame.model;
using winAppGame.service;

namespace winAppGame.service.rulechecker
{
    /// <summary>
    /// author:zuowenjun
    /// copyright:www.zuowenjun.cn
    /// 3带2、3带2的顺子出牌规则检查器
    /// </summary>
    public class ThreeWithDoublePaiRuleChecker : PaiRuleChecker
    {
        public override int ForBaseCount => 5;

        public override int ForIncrementCount => 5;

        public override List<PaiRuleType.PaiRuleTypeItem> ForRuleTypes => BuildPaiRuleTypeItems(PaiRuleType.ThreeWithDouble, PaiRuleType.ThreeWithDoubleMore);

        protected override PaiRuleCheckResult DoCheckAllowShowPais(List<Pai> selectedPais, List<Pai> lastShowPais, PaiRuleCheckContext checkContext)
        {
            var compare = ComparePais(selectedPais, lastShowPais, 3);

            if (compare > 0)
            {
                return PaiRuleCheckResult.Pass(checkContext.SelectedRuleType);
            }

            return PaiRuleCheckResult.Failed("出牌数值<=上家已出牌数值！");
        }

        protected override PaiRuleCheckResult DoCheckSelectedPais(List<Pai> selectedPais, PaiRuleCheckContext checkContext)
        {
            var groupDic = ConvertToDictionary(selectedPais);
            int threePaiCount = groupDic.Where(p => p.Value == 3).Count();
            int doublePaiCount = groupDic.Where(p => p.Value == 2).Count();

            if (threePaiCount != doublePaiCount)
            {
                return PaiRuleCheckResult.Failed("出牌张数不正确，3带2必需至少5张或5的倍数张！");
            }

            if (selectedPais.Count != threePaiCount * 3 + doublePaiCount * 2)
            {
                return PaiRuleCheckResult.Failed("出牌张数不正确，3带2必需至少5张或5的倍数张！");
            }

            var threePaiValues = groupDic.Where(p => p.Value == 3).Select(p => p.Key).ToList();

            if (!IsSerial(threePaiValues))
            {
                return PaiRuleCheckResult.Failed("出牌规则不正确，多个3带2必需每个3张牌数值是连续的！");
            }

            checkContext.SelectedRuleType = threePaiCount > 1 ? PaiRuleType.ThreeWithDoubleMore : PaiRuleType.ThreeWithDouble;
            return PaiRuleCheckResult.Pass(checkContext.SelectedRuleType);
        }


        public override PaiRuleCheckResult AutoSelectPais(IDictionary<Pai, int> groupPais, IEnumerable<Pai> lastShowPais, PaiRuleType.PaiRuleTypeItem showRuleType)
        {
            var threeGroupPais = groupPais.Where(kv => kv.Value >= 3).OrderBy(kv => kv.Key).Select(kv => kv);
            //排除掉已选3个的牌
            var remainderGroupPais = groupPais.Except(threeGroupPais, new LambdaEqualityComparer<KeyValuePair<Pai, int>>((x, y) => x.Key == y.Key));

            var doubleGroupPais = remainderGroupPais.Where(kv => kv.Value >= 2).OrderBy(kv => kv.Key).Select(kv => kv);

            if (lastShowPais.HasItem())
            {
                var lastShowThreePais = ConvertToDictionary(lastShowPais).Where(kv => kv.Value == 3).AsEnumerable();
                var lastShowMinPai = lastShowThreePais.Min(kv => kv.Key);
                threeGroupPais = threeGroupPais.Where(kv => kv.Key > lastShowMinPai).OrderBy(kv => kv.Key).Select(kv => kv);
                return DoAutoSelectPais(threeGroupPais, doubleGroupPais, lastShowThreePais, showRuleType);
            }
            else
            {
                return DoAutoSelectPais(threeGroupPais, doubleGroupPais, null, showRuleType);
            }
        }

        private PaiRuleCheckResult DoAutoSelectPais(IEnumerable<KeyValuePair<Pai, int>> threeGroupPais, IEnumerable<KeyValuePair<Pai, int>> doubleGroupPais, IEnumerable<KeyValuePair<Pai, int>> lastShowThreePais, PaiRuleType.PaiRuleTypeItem showRuleType)
        {
            if (!threeGroupPais.HasItem() || !doubleGroupPais.HasItem())
            {
                return PaiRuleCheckResult.Failed("要不起！");
            }

            Pai prePai = null;
            int forIndex = 0;
            Dictionary<Pai, int> okPais = new Dictionary<Pai, int>();
            int lowShowPaisCount = lastShowThreePais.HasItem() ? lastShowThreePais.Count() : 2;

            if (showRuleType == PaiRuleType.ThreeWithDouble)
            {
                var selectedPaiKv = threeGroupPais.OrderBy(kv => kv.Value).First();
                okPais[selectedPaiKv.Key] = 3;

                var selectedDoubleGroupPai = doubleGroupPais.OrderBy(kv => kv.Value).First();
                okPais[selectedDoubleGroupPai.Key] = 2;
                return PaiRuleCheckResult.Pass(PaiRuleType.ThreeWithDouble, okPais);
            }

            foreach (var kv in threeGroupPais)
            {
                forIndex++;

                if (prePai != null)
                {
                    if (prePai + 1 != kv.Key)
                    {
                        if (forIndex >= threeGroupPais.Count() || forIndex > lowShowPaisCount)
                        {
                            //若最后一张牌 或 已达到连续2个3张及以上，则中止
                            break;
                        }
                        //否则重置，重新检测连续
                        okPais.Clear();
                        forIndex = 1;
                    }
                    else if (lastShowThreePais.HasItem() && okPais.Count() == lastShowThreePais.Count())
                    {
                        //若满足上家出牌张数则中止
                        break;
                    }
                }

                prePai = kv.Key;
                okPais.Add(kv.Key, 3);
            }

            if (okPais.Count() < lowShowPaisCount || okPais.Count() < doubleGroupPais.Count())
            {
                //如果3张的小于2个连续 或 3张的连续个数<对子的连续个数，则说明无法构成3+3+N+2+N的出牌规则
                return PaiRuleCheckResult.Failed("要不起！");
            }

            //选择对应个数的对子的牌添加到出牌集合中okPais
            var selectedDoubleGroupPais = doubleGroupPais.Take(okPais.Count());
            foreach (var kv in selectedDoubleGroupPais)
            {
                okPais[kv.Key] = 2;
            }

            return PaiRuleCheckResult.Pass(PaiRuleType.ThreeWithDoubleMore, okPais);

        }
    }
}
